package com.qdlc.p2p.biz.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.qdlc.p2p.biz.executer.AbstractExecuter;
import com.qdlc.p2p.biz.executer.ExecuterHelper;
import com.qdlc.p2p.biz.executer.impl.FlowBorrowSuccessExecuter;
import com.qdlc.p2p.biz.executer.impl.FlowTenderSuccessExecuter;
import com.qdlc.p2p.biz.executer.impl.FlowTenderWaitMoneyExecuter;
import com.qdlc.p2p.biz.service.AccountService;
import com.qdlc.p2p.biz.service.FinanFlowService;
import com.qdlc.p2p.biz.task.ConcurrentUtil;
import com.qdlc.p2p.biz.tpp.TppBaseInterface;
import com.qdlc.p2p.biz.tpp.TppServiceFactory;
import com.qdlc.p2p.common.constant.Global;
import com.qdlc.p2p.common.constant.LogTplNid;
import com.qdlc.p2p.common.exception.FinanFlowExecption;
import com.qdlc.p2p.common.util.BeanUtil;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.DateUtil;
import com.qdlc.p2p.common.util.MessageUtil;
import com.qdlc.p2p.common.util.OrderNoUtil;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.dao.AdditionalFlowInvestorDao;
import com.qdlc.p2p.dal.dao.AdditionalFlowProjectDao;
import com.qdlc.p2p.dal.dao.AdditionalFlowRepayPlanDao;
import com.qdlc.p2p.dal.dao.AdditionalFlowUploadDao;
import com.qdlc.p2p.dal.dao.AdditionalFlowYieldPlanDao;
import com.qdlc.p2p.dal.dto.AdditionalFlowInvestor;
import com.qdlc.p2p.dal.dto.AdditionalFlowProject;
import com.qdlc.p2p.dal.dto.AdditionalFlowRepayPlan;
import com.qdlc.p2p.dal.dto.AdditionalFlowUpload;
import com.qdlc.p2p.dal.dto.AdditionalFlowYieldPlan;
import com.qdlc.p2p.dal.dto.Tpp;
import com.qdlc.p2p.dal.dto.User;
import com.qdlc.p2p.dal.model.FlowInvestorModel;
import com.qdlc.p2p.dal.model.FlowProjectModel;
import com.qdlc.p2p.dal.model.RepayPlanModel;
import com.qdlc.p2p.dal.model.TppModel;
import com.qdlc.p2p.dal.model.interest.InterestCalculator;
import com.qdlc.p2p.dal.util.UserUtils;

/**
 * 流转计划核心业务处理，包含发布，购买，审核，还款
 * 其他项目查询相关方法，单独使用service处理
 *
 * @author wjx
 * @version 2.0
 * @date 2015年5月18日 下午4:48:08
 */
@Repository("finanFlowService")
@Transactional
public class FinanFlowServiceImpl implements FinanFlowService {

    private static Logger logger = Logger.getLogger(FinanFlowServiceImpl.class);

    private static String WEB_URL = SystemConfigHelper.getValue(SystemConfigHelper.Nid.WEB_URL);

    @Resource
    private AdditionalFlowProjectDao additionalFlowProjectDao;

    @Resource
    private AdditionalFlowYieldPlanDao additionalFlowYieldPlanDao;

    @Resource
    private AdditionalFlowRepayPlanDao additionalFlowRepayPlanDao;

    @Resource
    private AdditionalFlowInvestorDao additionalFlowInvestorDao;

    @Resource
    private AdditionalFlowUploadDao additionalFlowUploadDao;

    @Resource
    private AccountService accountService;

    @Override
    public AdditionalFlowProject getFlowProjectByUuid(String uuid) {
        return additionalFlowProjectDao.getFlowProjectByUuid(uuid);
    }

    @Override
    public void addFlowProject(FlowProjectModel model, User user, List<AdditionalFlowUpload> list) {
        model.doTotalCopies();
        AdditionalFlowProject project = model.prototype();
        project.setUser(user);
        project.setStatus(FlowProjectModel.PROJECT_ADD_STATUS);
        project.setUuid(OrderNoUtil.getInstance().getSerialNumber());
        project.setAddTime(DateUtil.getNow());
        AdditionalFlowProject flow = additionalFlowProjectDao.save(project);
        for (AdditionalFlowUpload u : list) {
            u.setFlowProject(flow);
        }
        additionalFlowUploadDao.save(list);
    }

    @Override
    public void verifyFlowProject(FlowProjectModel model) {
        AdditionalFlowProject project = additionalFlowProjectDao.find(model.getId());
        if (model.getStatus() == 0) { //审核不通过
            project.setStatus(FlowProjectModel.PROJECT_VERIFY_FAIL_STATUS);
        } else if (model.getStatus() == 1) { //审核通过
            project.setStatus(FlowProjectModel.PROJECT_VERIFY_SUCCESS_STATUS);
        }
        project.setVerifyTime(DateUtil.getNow());
        project.setOperator(model.getOperator());
        project.setVerifyRemark(model.getVerifyRemark());
        additionalFlowProjectDao.update(project);
    }

    @Override
    public AdditionalFlowInvestor addFlowInvestor(AdditionalFlowProject flowProject, FlowProjectModel flowModel) {
        logger.info("进入购买理财产品开始");
        //校验是否该笔投标已经处理
        AdditionalFlowInvestor inv = additionalFlowInvestorDao.getFlowInvestorByNo(flowModel.getSubOrdId());
        if (null != inv) {
            logger.info("该投资已经处理，订单号：" + flowModel.getSubOrdId() + ",投标记录id：" + inv.getId());
            return inv;
        }

        //获取最新理财产品数据
        flowProject = additionalFlowProjectDao.find(flowProject.getId());
        int surplusCount = flowProject.getTotalCopies() - flowProject.getYesCopies(); //计算剩余份数
        if (surplusCount <= flowProject.getStartCopies()) {
            //校验购买份数是否等于剩余份数
            if (flowModel.getYesCopies() != surplusCount) {
                throw new FinanFlowExecption(MessageUtil.getMessage("MF103002009"));
            }
        } else {
            //校验购买份数是否小于起投份数
            if (flowModel.getYesCopies() < flowProject.getStartCopies()) {
                throw new FinanFlowExecption(MessageUtil.getMessage("MF103002010"));
            }
        }
        //校验购买份数是否超出剩余可买份数
        if (flowModel.getYesCopies() > surplusCount) {
            throw new FinanFlowExecption(MessageUtil.getMessage("MF103002001"));
        }

        int totalCount = flowModel.getYesCopies();  //购买份数
        double totalMoney = BigDecimalUtil.mul(flowProject.getEachMoney(), totalCount);  //计算用户购买金额
        AdditionalFlowInvestor flowInvestor = flowInvestor(flowModel);
        flowInvestor.setFlowProject(flowProject);
        flowInvestor.setUser(flowModel.getUser());
        flowInvestor.setBuyMoney(totalMoney);
        FlowProjectModel model = FlowProjectModel.instance(flowProject);

        model.checkTender(flowInvestor);
        Global.setTransfer("project", flowProject);
        Global.setTransfer("money", flowInvestor.getBuyMoney());
        AbstractExecuter flowTenderSuccessExecuter = ExecuterHelper.getExecuter(FlowTenderSuccessExecuter.class);
        flowTenderSuccessExecuter.execute(flowInvestor.getBuyMoney(), flowInvestor.getUser(), flowProject.getUser());

        //利息计算器生成待收计划
        InterestCalculator ic = model.interestCalculator(totalMoney);
        model.buySuccess(flowInvestor, ic);
        List<AdditionalFlowYieldPlan> yieldPlanList = model.createYieldPlanList(flowInvestor, ic);
        additionalFlowYieldPlanDao.save(yieldPlanList);
        //根据投资人待收计划，生成待还计划
        List<AdditionalFlowRepayPlan> repayList = model.createRepayList(yieldPlanList);
        additionalFlowRepayPlanDao.save(repayList);
        //添加待收收益记录
        double totalcoll = BigDecimalUtil.add(flowInvestor.getWaitYields(), flowInvestor.getBuyMoney());

        //扣除投资人资金
        Global.setTransfer("project", flowProject);
        Global.setTransfer("money", totalcoll);
        AbstractExecuter flowTenderWaitMoneyExecuter = ExecuterHelper.getExecuter(FlowTenderWaitMoneyExecuter.class);
        flowTenderWaitMoneyExecuter.execute(totalcoll, flowInvestor.getUser(), flowProject.getUser());

        //借款入账
        Global.setTransfer("project", flowProject);
        Global.setTransfer("money", flowInvestor.getBuyMoney());
        AbstractExecuter flowBorrowSuccessExecuter = ExecuterHelper.getExecuter(FlowBorrowSuccessExecuter.class);
        flowBorrowSuccessExecuter.execute(flowInvestor.getBuyMoney(), flowProject.getUser(), flowInvestor.getUser());

        //判断已购份数是否达到项目上线，更新借款标记状态
        int newTotal = flowProject.getYesCopies() + totalCount;
        flowProject.setYesCopies(newTotal);
        if (newTotal >= flowProject.getTotalCopies()) {
            flowProject.setStatus(FlowProjectModel.PROJECT_TENDER_OVER_STATUS);
            additionalFlowProjectDao.update(flowProject);
        }
        //触发接口转账接口，接口出发失败，直接整个业务回滚
        TppModel tppModel = new TppModel();
        tppModel.setOrderId(OrderNoUtil.getInstance().getSerialNumber());
        tppModel.setSubOrdId(flowModel.getSubOrdId());
        tppModel.setSubOrdDate(flowModel.getSubOrdDate());
        tppModel.setMoney(flowInvestor.getBuyMoney());
        tppModel.setTppUserCustId(UserUtils.getUserTppCustId(flowInvestor.getUser().getUserId()));
        tppModel.setToTppUserCustId(UserUtils.getUserTppCustId(flowProject.getUser().getUserId()));
        tppModel.setOrderDate(DateUtil.dateStr7(DateUtil.getNow()));
        TppBaseInterface tppService = TppServiceFactory.newIntance();
        tppService.tppLoan(tppModel);
        //更新投标对象
        flowInvestor.setTppTenderOrder(flowModel.getSubOrdId());
        flowInvestor.setTppTenderDate(flowModel.getSubOrdDate());
        additionalFlowInvestorDao.update(flowInvestor);
        logger.info("处理完成");
        return flowInvestor;
    }

    /**
     * 封装理财人信息
     *
     * @param flowModel
     * @return
     */
    private AdditionalFlowInvestor flowInvestor(FlowProjectModel flowModel) {
        AdditionalFlowInvestor flowInvestor = new AdditionalFlowInvestor();
        flowInvestor.setBuyCopies(flowModel.getYesCopies());
        flowInvestor.setAddTime(DateUtil.getNow());
        flowInvestor.setTppTenderOrder(flowModel.getSubOrdId());
        return flowInvestor;
    }

    @Override
    public void autoFlowRepay(AdditionalFlowRepayPlan repayPlan) {
        repayPlan = additionalFlowRepayPlanDao.find(repayPlan.getId());
        repayPlan.setWebStatus((byte) 1);
        logger.info("理财还款进入，rId:" + repayPlan.getId() + ",fPId:" + repayPlan.getFlowProject().getId());
        //重新获取repayPlan数据，避免出现原始数据
        checkFlowRepay(repayPlan);
        RepayPlanModel repayModel = RepayPlanModel.instance(repayPlan);
        repayModel.checkRepayUser();
        //处理还款人资金信息
        flowRepayHandleBorrow(repayModel);

        //处理还款记录
        repayPlan.setRepayYestime(DateUtil.getNow());
        repayPlan.setRepayYescopies(repayModel.getRepayCopies());
        repayPlan.setRepayYesmoney(repayModel.getRepayMoney());
        //处理理财人资金信息
        flowRepayHandleTender(repayModel);
        repayPlan.setStatus((byte) 1);
        additionalFlowRepayPlanDao.update(repayPlan);
        //校验是否已经将所有待还全部还款
        repayModel.checkAllRepayProject();
        logger.info("流转计划还款处理完成");
    }

    /**
     * 处理还款人资金
     */
    private void flowRepayHandleBorrow(RepayPlanModel repayModel) {
        //获取借款人资金信息
        User user = repayModel.getUser();
        AdditionalFlowYieldPlanDao yieldPlanDao = BeanUtil.getBean(AdditionalFlowYieldPlanDao.class);
        long yieldId = repayModel.getYieldPlanId();
        AdditionalFlowYieldPlan yieldPlan = yieldPlanDao.find(yieldId);
        User yieldUser = yieldPlan.getUser();

        //扣除应还本金
        double money = repayModel.getRepayMoney();
        Global.setTransfer(LogTplNid.LOG_TPL_KEY, LogTplNid.FLOW_MONEY_REPAY);
        Global.setTransfer("web_url", WEB_URL);
        Global.setTransfer("project", repayModel.getFlowProject());
        Global.setTransfer("money", money);
        accountService.deductUseMoneyAndTotal(user.getUserId(), yieldUser.getUserId(), money);

        //扣除收益
        double copie = repayModel.getRepayCopies();
        Global.setTransfer(LogTplNid.LOG_TPL_KEY, LogTplNid.FLOW_MONEY_REPAY);
        Global.setTransfer("web_url", WEB_URL);
        Global.setTransfer("project", repayModel.getFlowProject());
        Global.setTransfer("money", copie);
        accountService.deductUseMoneyAndTotal(user.getUserId(), yieldUser.getUserId(), copie);
    }

    /**
     * 还款，校验还款计划状态
     *
     * @param repayPlan
     * @return
     */
    private AdditionalFlowRepayPlan checkFlowRepay(AdditionalFlowRepayPlan repayPlan) {
        if (repayPlan.getStatus() == 1) {
            throw new FinanFlowExecption(MessageUtil.getMessage("MF103003001"));
        }
        return repayPlan;
    }


    /**
     * 处理理财人收益
     */
    private void flowRepayHandleTender(AdditionalFlowRepayPlan repayPlan) {
        AdditionalFlowYieldPlanDao yieldPlanDao = BeanUtil.getBean(AdditionalFlowYieldPlanDao.class);
        AdditionalFlowInvestorDao flowInvestorDao = BeanUtil.getBean(AdditionalFlowInvestorDao.class);
        long yieldId = repayPlan.getYieldPlanId();
        AdditionalFlowYieldPlan yieldPlan = yieldPlanDao.find(yieldId);
        User user = yieldPlan.getUser();
        long userId = user.getUserId();
        long toUserId = repayPlan.getUser().getUserId();

        //本金收回
        double money = yieldPlan.getWaitMoney();
        Global.setTransfer(LogTplNid.LOG_TPL_KEY, LogTplNid.FLOW_MONEY_BACK);
        Global.setTransfer("web_url", SystemConfigHelper.getValue(SystemConfigHelper.Nid.WEB_URL));
        Global.setTransfer("project", repayPlan.getFlowProject());
        Global.setTransfer("money", money);
        accountService.revokeCapital(userId, toUserId, money);

        //预期收益收回
        double copie = yieldPlan.getWaitYields();
        Global.setTransfer(LogTplNid.LOG_TPL_KEY, LogTplNid.FLOW_RECE);
        Global.setTransfer("web_url", SystemConfigHelper.getValue(SystemConfigHelper.Nid.WEB_URL));
        Global.setTransfer("project", repayPlan.getFlowProject());
        Global.setTransfer("money", copie);
        accountService.revokeCapital(userId, toUserId, copie);

        //更新理财待收记录
        yieldPlan.setYesMoney(money);
        yieldPlan.setYesYidlds(copie);
        yieldPlan.setYesTime(DateUtil.getNow());
        yieldPlan.setStatus((byte) 1);
        yieldPlanDao.update(yieldPlan);

        //更新投资人记录
        AdditionalFlowInvestor flowInvstor = yieldPlan.getFlowInvestor();
        AdditionalFlowProject flowProject = yieldPlan.getFlowProject();
        if (flowProject.getIsDay() == 1) {
            flowInvstor.setStatus(FlowInvestorModel.YIELD_PLAN_REPAY_STATUS);
        } else {
            if (yieldPlan.getPeriod() == flowProject.getTimeLimit() - 1) { //是最后一期还款
                flowInvstor.setStatus(FlowInvestorModel.YIELD_PLAN_REPAY_STATUS);
            }
        }
        double yesMoney = flowInvstor.getYesMoney();
        double yesCopi = flowInvstor.getYesYields();

        double newYesMoney = BigDecimalUtil.add(yesMoney, money); //还款后金额
        double newCopi = BigDecimalUtil.add(yesCopi, copie); //还款后收益
        flowInvstor.setYesYields(newCopi);
        flowInvstor.setYesMoney(newYesMoney);
        flowInvestorDao.update(flowInvstor);
        double totalAccount = BigDecimalUtil.add(money, copie);
        List<TppModel> taskList = new ArrayList<TppModel>();
        Tpp tpp = new Tpp(TppModel.BORROWVERIFYFULLSUCCESS, TppModel.TPP_REPAY, flowInvstor.getFlowProject().getUser(), flowInvstor.getUser(), totalAccount, null);
        tpp.setServFee(0);
        tpp.setSubOrdId(flowInvstor.getTppTenderOrder());
        tpp.setSubOrdDate(flowInvstor.getTppTenderDate());
        TppModel tppModel = TppModel.instance(tpp);
        taskList.add(tppModel);
        // 第三方还款业务
        ConcurrentUtil.tppTask(taskList);
        //TODO: 需要添加到队列中处理！
    }

}
